/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2017 by Hitachi Vantara : http://www.pentaho.com
 *
 *******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/

package org.pentaho.di.trans.steps.metainject;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.ObjectLocationSpecificationMethod;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.extension.ExtensionPoint;
import org.pentaho.di.core.extension.ExtensionPointInterface;
import org.pentaho.di.core.logging.LogChannelInterface;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.core.vfs.KettleVFS;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.metastore.api.IMetaStore;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@ExtensionPoint(
    id = "RepositoryExporterPatchTransStep",
    description = "Patch the step in a transformation during repository export",
    extensionPointId = "RepositoryExporterPatchTransStep" )
public class RepositoryExporterExtension implements ExtensionPointInterface {

  @Override
  public void callExtensionPoint(LogChannelInterface log, Object object ) throws KettleException{

    Object[] metaInjectObjectArray = (Object[]) object;
    TransMeta transMeta = (TransMeta) metaInjectObjectArray[0];
    Class<?> PKG = (Class<?>) metaInjectObjectArray[1];
//    KettleFileRepository fileRep = (KettleFileRepository) metaInjectObjectArray[2];
    Class fileRep= (Class) metaInjectObjectArray[2];
    Field f= null;
    try {
      f = fileRep.getDeclaredField("metaStore");
      IMetaStore metaStore = (IMetaStore) f.get( this );
      StepMeta stepMeta = (StepMeta) metaInjectObjectArray[3];

      if ( stepMeta.isEtlMetaInject() ) {
        Class metaInjectMeta = Class.forName("org.pentaho.di.trans.steps.metainject.MetaInjectMeta", true, object.getClass().getClassLoader());
//      MetaInjectMeta metaInjectMeta = (MetaInjectMeta) stepMeta.getStepMetaInterface();
        // convert to a named based reference.
        //
        Method specificationMethod = metaInjectMeta.getMethod("getSpecificationMethod",null);
        if ( specificationMethod.invoke(null) == ObjectLocationSpecificationMethod.FILENAME ) {
          try {
            Method loadTrans = metaInjectMeta.getMethod("loadTransformationMeta",metaInjectMeta, Repository.class,
                    IMetaStore.class, VariableSpace.class);
//          TransMeta meta =
//              MetaInjectMeta.loadTransformationMeta( metaInjectMeta, fileRep, metaStore, transMeta );
            TransMeta meta =
                    (TransMeta) loadTrans.invoke( metaInjectMeta, fileRep, metaStore, transMeta );
            FileObject fileObject = KettleVFS.getFileObject( meta.getFilename() );

//          metaInjectMeta.setSpecificationMethod( ObjectLocationSpecificationMethod.REPOSITORY_BY_NAME );
            Field specification = metaInjectMeta.getDeclaredField("specificationMethod");
            specification.set(metaInjectMeta,ObjectLocationSpecificationMethod.REPOSITORY_BY_NAME);
//          metaInjectMeta.setFileName( null );
            Field fileName = metaInjectMeta.getDeclaredField("fileName");
            fileName.set(metaInjectMeta,null);
//          metaInjectMeta.setTransName( meta.getName() );
            Field transName = metaInjectMeta.getDeclaredField("transName");
            transName.set(metaInjectMeta,null);
//          metaInjectMeta.setDirectoryPath( Const.NVL( calcRepositoryDirectory( fileRep, fileObject ), "/" ) );
            Field directoryPath = metaInjectMeta.getDeclaredField("directoryPath");
            directoryPath.set(metaInjectMeta, Const.NVL( calcRepositoryDirectory( fileRep, fileObject ), "/" ) );
          } catch ( Exception e ) {
            log.logError( BaseMessages.getString( PKG, "Repository.Exporter.Log.UnableToLoadTransInMDI",
                    metaInjectMeta.getName() ), e );
          }
        }
      }
    } catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {
      e.printStackTrace();
    }

  }

  private String calcRepositoryDirectory(Object fileRepObj, FileObject fileObject ) throws FileSystemException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    Class fileRep = fileRepObj.getClass();
    String path = fileObject.getParent().getName().getPath();
    Method repoMeta = fileRep.getMethod("getRepositoryMeta",null);

    Class repMeta = (Class) repoMeta.invoke(null);
    Method basedir = repMeta.getMethod("getBaseDirectory",null);
    String baseDirectory = (String) basedir.invoke(null);
    // Double check!
    //
    if ( path.startsWith( baseDirectory ) ) {
      return path.substring( baseDirectory.length() );
    } else {
      return path;
    }
  }
}
